// Copyright (C) 2002, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

#include "CoinPragma.hpp"
#include "ClpSimplex.hpp"
#include "ClpDualRowDantzig.hpp"
#include "ClpFactorization.hpp"
#include "CoinIndexedVector.hpp"
#include "CoinHelperFunctions.hpp"
#ifndef CLP_DUAL_COLUMN_MULTIPLIER
#define CLP_DUAL_COLUMN_MULTIPLIER 1.01
#endif

//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################

//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
ClpDualRowDantzig::ClpDualRowDantzig()
  : ClpDualRowPivot()
{
  type_ = 1;
}

//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
ClpDualRowDantzig::ClpDualRowDantzig(const ClpDualRowDantzig &source)
  : ClpDualRowPivot(source)
{
}

//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
ClpDualRowDantzig::~ClpDualRowDantzig()
{
}

//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpDualRowDantzig &
ClpDualRowDantzig::operator=(const ClpDualRowDantzig &rhs)
{
  if (this != &rhs) {
    ClpDualRowPivot::operator=(rhs);
  }
  return *this;
}

// Returns pivot row, -1 if none
int ClpDualRowDantzig::pivotRow()
{
  assert(model_);
  int iRow;
  const int *pivotVariable = model_->pivotVariable();
  double tolerance = model_->currentPrimalTolerance();
  // we can't really trust infeasibilities if there is primal error
  if (model_->largestPrimalError() > 1.0e-8)
    tolerance *= model_->largestPrimalError() / 1.0e-8;
  double largest = 0.0;
  int chosenRow = -1;
  int numberRows = model_->numberRows();
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
  int numberColumns = model_->numberColumns();
#endif
  for (iRow = 0; iRow < numberRows; iRow++) {
    int iSequence = pivotVariable[iRow];
    double value = model_->solution(iSequence);
    double lower = model_->lower(iSequence);
    double upper = model_->upper(iSequence);
    double infeas = std::max(value - upper, lower - value);
    if (infeas > tolerance) {
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
      if (iSequence < numberColumns)
        infeas *= CLP_DUAL_COLUMN_MULTIPLIER;
#endif
      if (infeas > largest) {
        if (!model_->flagged(iSequence)) {
          chosenRow = iRow;
          largest = infeas;
        }
      }
    }
  }
  return chosenRow;
}
// FT update and returns pivot alpha
double
ClpDualRowDantzig::updateWeights(CoinIndexedVector * /*input*/,
  CoinIndexedVector *spare,
  CoinIndexedVector * /*spare2*/,
  CoinIndexedVector *updatedColumn)
{
  // Do FT update
  model_->factorization()->updateColumnFT(spare, updatedColumn);
  // pivot element
  double alpha = 0.0;
  // look at updated column
  double *work = updatedColumn->denseVector();
  int number = updatedColumn->getNumElements();
  int *which = updatedColumn->getIndices();
  int i;
  int pivotRow = model_->pivotRow();

  if (updatedColumn->packedMode()) {
    for (i = 0; i < number; i++) {
      int iRow = which[i];
      if (iRow == pivotRow) {
        alpha = work[i];
        break;
      }
    }
  } else {
    alpha = work[pivotRow];
  }
  return alpha;
}

/* Updates primal solution (and maybe list of candidates)
   Uses input vector which it deletes
   Computes change in objective function
*/
void ClpDualRowDantzig::updatePrimalSolution(CoinIndexedVector *primalUpdate,
  double primalRatio,
  double &objectiveChange)
{
  double *work = primalUpdate->denseVector();
  int number = primalUpdate->getNumElements();
  int *which = primalUpdate->getIndices();
  int i;
  double changeObj = 0.0;
  const int *pivotVariable = model_->pivotVariable();
  if (primalUpdate->packedMode()) {
    for (i = 0; i < number; i++) {
      int iRow = which[i];
      int iPivot = pivotVariable[iRow];
      double &value = model_->solutionAddress(iPivot);
      double cost = model_->cost(iPivot);
      double change = primalRatio * work[i];
      value -= change;
      changeObj -= change * cost;
      work[i] = 0.0;
    }
  } else {
    for (i = 0; i < number; i++) {
      int iRow = which[i];
      int iPivot = pivotVariable[iRow];
      double &value = model_->solutionAddress(iPivot);
      double cost = model_->cost(iPivot);
      double change = primalRatio * work[iRow];
      value -= change;
      changeObj -= change * cost;
      work[iRow] = 0.0;
    }
  }
  primalUpdate->setNumElements(0);
  objectiveChange += changeObj;
}
//-------------------------------------------------------------------
// Clone
//-------------------------------------------------------------------
ClpDualRowPivot *ClpDualRowDantzig::clone(bool CopyData) const
{
  if (CopyData) {
    return new ClpDualRowDantzig(*this);
  } else {
    return new ClpDualRowDantzig();
  }
}

/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
*/
